I am a bit confused with the definition of class inside a function.
Usually while defining class inside a function, we define it as follows:
def dude():
class swaroop(object)
What if there is no object at all and the function goes like this:
def dude():
class swaroop():
What does this mean?
The class(object) syntax is an example of inheritance. If you remove the inherited object, then the class that you create inherits from nothing and is therefore a new class. Because you're defining it within a function, it can only be used within that scope.
Related
Declaring a variable in a class (outside of a function): all class functions can access it (basically a public variable)
Declaring a variable inside a function inside a class: only that function can access it (it's in that function's scope)
Declaring a variable with self.(variable name) inside a function inside a class: all class functions can access it (how is this different from global (variable name)?)
And since there is no private/protected, everything is public, so everything accessible from inside a class is accessible from outside the class.
Are there any other nuances I should know, or have I pretty much got it?
Since the listing in your question is not 100% clear, I've decided to explain it with a simple example. It also includes some things like __something variables you did not mention in your list.
class Test:
a = None
b = None
def __init__(self, a):
print self.a
self.a = a
self._x = 123
self.__y = 123
b = 'meow'
At the beginning, a and b are only variables defined for the class itself - accessible via Test.a and Test.b and not specific to any instance.
When creating an instance of that class (which results in __init__ being executed):
print self.a doesn't find an instance variable and thus returns the class variable
self.a = a: a new instance variable a is created. This shadows the class variable so self.a will now reference the instance variable; to access the class variable you now have to use Test.a
The assignment to self._x creates a new instance variable. It's considered "not part of the public API" (aka protected) but technically it has no different behaviour.
The assignment to self.__y creates a new instance variable named _Test__y, i.e. its name is mangled so unless you use the mangled name it cannot be accessed from outside the class. This could be used for "private" variables.
The assignment to b creates a local variable. It is not available from anywhere but the __init__ function as it's not saved in the instance, class or global scope.
Declaring a variable at the top level of the class is like declaring a static or class variable. Qualifying it with self is declaring an instance variable. Class variables can be modified by referring to them by class name (e.g. Class.x = 5) and all instances will inherit these changes. Instance variables are private to an instance and can only be modified by that instance.
You can achieve some level of access control using underscores. See private variables in the Python tutorial. By convention, variables starting with one underscore, e.g. _foo are non-public parts of an API, and names starting with two underscores e.g. __foo will have it's name mangled to be _classname__foo.
Although answered, let me add some comments to your questions:
Declaring a variable in a class (outside of a function) : all class functions can access it (basically a public variable)
This is like a static variable and can be called using the class name. These variables are available to all functions, any functions can modify it and print it.
Declaring a variable inside a function inside a class : only that function can access it (it's in that function's scope):
If the variable is declared without self then it is accessible within that function only, like a local variable. However, if it was declared using self like self.var= 'somevalue', then it is accessible via any object but not via the class name.
Declaring a variable with self.(variable name) inside a function inside a class : all class functions can access it (how is this different from global (variable name)?)
See answer in the above part.
And since there is no private / protected, everything is public, so everything accessible from inside a class is accessible from outside the class
Yes, but we can use single underscore to tell the world this variable is private, but technically that actually doesn't make it private.
we can use the scope in this for as :
case 1: In the Class
class test:
def __init__(self, a):
self.__elements = a
def change_a(self): self.__elements = 5
case 2 : Outside class
t = test(5)
This will access by as object._classname__privatevaribalename
print(t._test__elements)
this will print the change value of a
I am looking the following python3 code:
class MyClass(MyAbstractClass):
:
def my_fun1(self, input1):
:
return result
Then at other part of the codes, MyClass is used like:
output = MyClass().my_fun1(input1)
I am wondering does MyClass().my_fun1(input1) instantiate an object of MyClass implicitly? Or MyClass() here is treated as a utility function class? If it is a utility function, why bother put it within a class? Or is it a static class? but it the my_fun1 isn't marked as a static function?
Sorry I am coming from C++/Java background, so this is a bit strange to me ...
Thanks a lot!
Calling MyClass().my_fun1(input1) instantiats an object of MyClass first (since MyClass() calls the constructor) and then calls my_fun1 function.
In Python, there is no static class, but we do have static method and class method. You could find many good references for these concepts such as HERE and HERE.
If you define a static method in MyClass, you will need to call it in the following manner:
output = MyClass.my_static_method(input1)
Note that there is no () after MyClass, meaning you are not creating an object (instance).
I am currently trying to abstract/default some behaviour away. All children define some constants differently and I want to reference said variable in their parent class. My attempt looks something like this:
class Mother():
a= True
#staticmethod
def something():
return Mother.a
class Child(Mother):
a = False
print(Mother.something())
print(Child.something())
Mother.something() obviously produces True, but Child.something() should produce False.
This doesn't work as I guess in inheritance in Python you don't override the variables but just hides them outside of vision?
In the Child class, when something is called, Mother.a is still valid, you're referring to the parent Mother class (defined at Childs class declaration). Python has another builtin called classmethod for your use case:
class Mother():
a = True
#classmethod
def something(cls):
return cls.a
class Child(Mother): # Mother.a gets defined here
a = False
print(Mother.something()) # True
print(Child.something()) # False
From the docs:
Class methods are different than C++ or Java static methods. If you want those, see staticmethod().
#classmethods define cls (by convention, the variable doesn't have to be called cls) as the first argument, just like instance methods would receive self as their first argument. cls refers to the class that the method is being called on.
I'd recommend this video for a great introduction on best practices for classes and how/where to use all the special decorators/syntax in python.
Since you mentioned abstract classes, you may be interested in the abc module as well.
In one of my classes, I am printing data from another class that is yet to be initialized.I only want to print that data once the class has been initialized.Is there any way check if the class has been instantiated?
Two functions that return true if you pass an undeclared class, and false if it is instantiated:
import inspect
inspect.isclass(myclass)
or
isinstance(myclass, type)
In general, if it's not a type (i.e. undeclared class), it's an instantiated type.
Simply add a variable into the class to be made, like this:
class tobeinitiated():
initiated=False
def __init__(self):
global initiated
tobeinitiated.initiated = True
Then, where you need the information:
global initiated #(if in class)
if tobeinitiated.initiated:
#do the stuff you need to do
Hope this helps. :)
You can add a counter of instances in the constructor for example.
I have a class that has a basic method, and subclasses that have the same base functionality, but additional behaviour, which can be implemented with decorators.
class cls_with_basic_method:
#if...exec("#decoratorA")
#if...exec("#decoratorB")
#...
def basic_method(arg):
#...
return arg
class cls_with_basic_method_and_decoratorA(class_with_basic_method):
#...
class cls_with_basic_method_and_decoratorB(class_with_basic_method):
#...
#...
It seems the quickest solution would be if I were able to execute the particular decorator as the subclass method is called, but can't think of a way of expressing it in python. Can this easily be done?
A decorated function or method is usually a different object than the function or method it decorates [*] - so, you can just wrap the original class' method in an explict way. This is rather straightforawrd, and rather boring - but it will work if you need to decorate just a few methods of the sub-classes:
class cls_with_basic_method:
def basic_method(arg):
#...
return arg
class cls_with_basic_method_and_decoratorA(class_with_basic_method):
basic_method = decoratorA(cls_with_basic_method.basic_method)
class cls_with_basic_method_and_decoratorB(class_with_basic_method):
basic_method = decoratorB(cls_with_basic_method.basic_method)
The only special thing done there is use the decorators with the syntax of regular function calls instead of usign the "#..." syntax - this way they can be used inside the expressions.
This method is further boring due to you have to hardcode the superclass name within the class body at each decoration, since you can't use super from the class body, just from inside methods.
[*] Although some decorators just add metadata to the callable object they decorate and return the object itself - this approach won't work for such decorators, as they will affect the method in the superclass as well.
Now, taking your problem further - what you want is just to wrap arbitrary methods on the superclass when they are called on the subclasses. That can be done more or less automatically if you override the class__getattribute__ - you then could create a class hierarchy with an special "decorator" attribute that would be called for each method call - more or less like this:
class cls_with_basic_method:
_auto_decorate = set(("basic_method", ...))
_decorator = lambda x: x # NOP decorator
def basic_method(arg):
#...
return arg
def __getattribute__(self, attrname):
attr = object.__getattribute__(self, attr)
# shortcircuit non-method retrievelas as fast as possible:
if not attrname in __class__._auto_decorate not callable(attr):
return attr
return self.__class__._decorator(attr)
class cls_with_basic_method_and_decoratorA(class_with_basic_method):
_decorator = decoratorA
class cls_with_basic_method_and_decoratorB(class_with_basic_method):
_decorator = decoratorB
Of course, if you need different decorators for different methods, just change the code in __getattribute__ accordingly - the easiest way would be to make the _decorator attribute be a dictionary instead of pointing to a simple function.
(on a side note: the __class__ magic variable, when used inside a method, is a Python 3 thing: it automatically contains a reference to the class it is defined in (in this case, cls_with_basic_method).
This approach will redecorate the method on each call - it is not as much overhead as it seems to be - Python's default method retrieval mechanism itself is similarly complicated - but if you prefer to decorate the methods at class creation instead, tehn you can use a similar mechanism in a metaclass instead of relying on __getattribute__.
from itertools import chain
class AutoDecorate(type):
def __new__(metacls, name, bases, dct):
if "_decorator" not in dct:
dct["_decorator"] = lambda x: x # NOP decorator
all_bases = list(chain(base.__mro__ for base in bases))
for base in all_bases:
if not "_auto_decorate" in base.__dict__:
continue
for method_name in base.auto_decorate:
if method_name not in dct:
dct[method_name] = dct["_decorator"](getattr(base, method_name))
return super().__new__(name, bases, dct)
class cls_with_basic_method(metaclass=AutoDecorate):
_auto_decorate = set(("basic_method", ...))
def basic_method(arg):
#...
return arg
class cls_with_basic_method_and_decoratorA(class_with_basic_method):
_decorator = decoratorA
class cls_with_basic_method_and_decoratorB(class_with_basic_method):
_decorator = decoratorB
This is actually simpler than it might look: Upon creating a new class on the hierarchy, it just searches all superclasses for those which have the _auto_decorate attribute - and then it fetches the methods in that list, and decorate them with the decorator in the _decorator attribute of the class being created.
From what you are asking, I'd say you are dealing with a project where you need an "aspect oriented programing" approach. There are several Python libraries that can provide that functionality - maybe you should take a look at that. If you think so, search for modules that can provide appropriate Python aspect oriented capabilities and use those.