>>> class ObjectCreator(object): ... pass ... >>> my_object = ObjectCreator() >>> print my_object <__main__.ObjectCreator object at 0x8974f2c>
class
keyword is used, Python executes the command and creates an object . Instruction >>> class ObjectCreator(object): ... pass ...
ObjectCreator
.class
keyword: >>> def choose_class(name): ... if name == 'foo': ... class Foo(object): ... pass ... return Foo # , ... else: ... class Bar(object): ... pass ... return Bar ... >>> MyClass = choose_class('foo') >>> print MyClass # , <class '__main__.Foo'> >>> print MyClass() # <__main__.Foo object at 0x89c6d4c>
class
keyword is used, Python creates this object automatically. But like most things in Python, there is a way to do it manually.type
function? Good old function that allows you to determine the type of object: >>> print type(1) <type 'int'> >>> print type("1") <type 'str'> >>> print type(ObjectCreator) <type 'type'> >>> print type(ObjectCreator()) <class '__main__.ObjectCreator'>
type
function has a completely different use: it can also create classes on the fly. type
takes a class description as input and convokes the class.type
works as follows: type(< >, < >, # , <, >)
>>> class MyShinyClass(object): ... pass
>>> MyShinyClass = type('MyShinyClass', (), {}) # - >>> print MyShinyClass <class '__main__.MyShinyClass'> >>> print MyShinyClass() # <__main__.MyShinyClass object at 0x8997cec>
type
accepts a dictionary that defines class attributes: >>> class Foo(object): ... bar = True
>>> Foo = type('Foo', (), {'bar':True})
>>> print Foo <class '__main__.Foo'> >>> print Foo.bar True >>> f = Foo() >>> print f <__main__.Foo object at 0x8a9b84c> >>> print f.bar True
>>> class FooChild(Foo): ... pass
>>> FooChild = type('FooChild', (Foo,), {}) >>> print FooChild <class '__main__.FooChild'> >>> print FooChild.bar # bar is inherited from Foo True
>>> def echo_bar(self): ... print self.bar ... >>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar}) >>> hasattr(Foo, 'echo_bar') >>> hasattr(FooChild, 'echo_bar') True >>> my_foo = FooChild() >>> my_foo.echo_bar() True
class
keyword is used, and it does this using metaclasses. MyClass = MetaClass() MyObject = MyClass()
type
allows you to do something like this: MyClass = type('MyClass', (), {})
type
function is actually a metaclass. type
is a metaclass that Python internally uses to create all classes.Type
?str
, the class for creating string objects, and int
, the class for creating integer objects. type
is just a class for creating class objects.__class__
attribute: >>> age = 35 >>> age.__class__ <type 'int'> >>> name = 'bob' >>> name.__class__ <type 'str'> >>> def foo(): pass >>> foo.__class__ <type 'function'> >>> class Bar(object): pass >>> b = Bar() >>> b.__class__ <class '__main__.Bar'>
__class__
for each __class__
? >>> a.__class__.__class__ <type 'type'> >>> age.__class__.__class__ <type 'type'> >>> foo.__class__.__class__ <type 'type'> >>> b.__class__.__class__ <type 'type'>
type
is a built-in metaclass that Python uses, but of course you can create your own.__metaclass__
attribute__metaclass__
: class Foo(object): __metaclass__ = something... [...]
Foo
class.class Foo(object)
, an object class is not yet created in memory.__metaclass__
in the class definition. If he finds it, he uses it to create the class Foo
. If not, it will use type
. class Foo(Bar): pass
Foo
class have the attribute __metaclass__
?Foo
, using what is specified in __metaclass__
.__metaclass__
, he searches for __metaclass__
in the parent class Bar
and tries to do the same.__metaclass__
is not in any of the parents, Python will search for __metaclass__
at the module level.__metaclass__
at all, he uses type
to create a class object.__metaclass__
?type
or any of its subclasses, as well as anything that uses them.__metaclass__
at the module level.__metaclass__
can be any callable object, not necessarily a formal class (I know that something with the word “class” in the name does not have to be a class, what nonsense? However, this is useful). # , # `type` def upper_attr(future_class_name, future_class_parents, future_class_attr): """ -, """ # , '__' attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) # uppercase_attr = dict((name.upper(), value) for name, value in attrs) # `type` return type(future_class_name, future_class_parents, uppercase_attr) __metaclass__ = upper_attr # class Foo(object): # __metaclass__ , bar = 'bip' print hasattr(Foo, 'bar') # Out: False print hasattr(Foo, 'BAR') # Out: True f = Foo() print f.BAR # Out: 'bip'
# , `type` , `str` `int`, # class UpperAttrMetaclass(type): # __new__ __init__ # , # __init__ , . # __new__, , # # , , # __new__. # - __init__, . # __call__, # . def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return type(future_class_name, future_class_parents, uppercase_attr)
type
and do not overload the call to the __new__
parent. Let's do that: class UpperAttrMetaclass(type): def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) # type.__new__ # , return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)
upperattr_metaclass
. There is nothing special about it: the method always receives the current instance as the first argument. In the same way as you use self
in normal methods.self
, there is an agreement on the naming of all these arguments. So the real metaclass looks something like this: class UpperAttrMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return type.__new__(cls, name, bases, uppercase_attr)
super
, which will cause inheritance (since, of course, you can create a metaclass inherited from a metaclass inherited from type
): class UpperAttrMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
__dict__
and the like.__metaclass__
accepts any callable object, why would you suddenly use a class if it’s obviously more difficult?UpperAttrMetaclass(type)
, you immediately know what will happen next.__new__
, __init__
and __call__
. Of course, you can usually do everything in __new__
, but some are more comfortable using __init__
Metaclasses are deep magic, about which 99% of users do not even need to think. If you think whether you need to use them - you do not need (people who really need them, know exactly why they need them, and do not need an explanation of why).
~ Guru Python Tim Peters
class Person(models.Model): name = models.CharField(max_length=30) age = models.IntegerField()
guy = Person(name='bob', age='35') print guy.age
IntegerField
, but int
, and the value can be obtained directly from the database.models.Model
defines __metaclass__
, which __metaclass__
some magic and turns the Person
class that we just defined with a simple expression into a complex database binding. >>> class Foo(object): pass >>> id(Foo) 142630324
type
.type
is its own metaclass. It cannot be reproduced on pure Python and is done with a small cheat at the implementation level.Source: https://habr.com/ru/post/145835/
All Articles