Все в Python является объектом
Python — это объектно-ориентированный язык, поэтому числа, строки, списки, наборы, словари, функции, классы и т. д. в Python — все это объекты.
использоватьtype()
Чтобы просмотреть различные типы объектов в Python
In [11]: # 数字
In [12]: type(10)
Out[12]: int
In [13]: type(3.1415926)
Out[13]: float
In [14]: # 字符串
In [15]: type('a')
Out[15]: str
In [16]: type("abc")
Out[16]: str
In [17]: # 列表
In [18]: type(list)
Out[18]: type
In [19]: type([])
Out[19]: list
In [20]: # 集合
In [21]: type(set)
Out[21]: type
In [22]: my_set = {1, 2, 3}
In [23]: type(my_set)
Out[23]: set
In [24]: # 字典
In [25]: type(dict)
Out[25]: type
In [26]: my_dict = {'name': 'hui'}
In [27]: type(my_dict)
Out[27]: dict
In [28]: # 函数
In [29]: def func():
...: pass
...:
In [30]: type(func)
Out[30]: function
In [31]: # 类
In [32]: class Foo(object):
...: pass
...:
In [33]: type(Foo)
Out[33]: type
In [34]: f = Foo()
In [35]: type(f)
Out[35]: __main__.Foo
In [36]: # type
In [37]: type(type)
Out[37]: type
Как можно заметить
- количество
1
датип intОбъект - нить
abc
датип улОбъект - Списки, множества, словаритип, созданные им объекты принадлежат
list、set、dict
Типы - функция
func
датип функцииОбъект - пользовательский класс
Foo
созданный объектf
даFoo
тип, сам его классFoo
являетсятипОбъект. - четное
type
сам является объектом типа type
1. Классы тоже объекты
Класс — это набор объектов с одинаковой функциональностью и одинаковыми свойствами.
В большинстве языков программированияКласс — это набор сегментов кода, описывающих, как создать объект.. Это по-прежнему верно в Python:
In [1]: class ObjectCreator(object):
...: pass
...:
In [2]: my_object = ObjectCreator()
In [3]: print(my_object)
<__main__.ObjectCreator object at 0x0000021257B5A248>
Однако классы в Python — это гораздо больше.Класс также является объектом. Да, верно, объект. только тыиспользовать ключевые словаclass
, интерпретатор Python создает объект при выполнении.
Фрагмент кода ниже:
>>> class ObjectCreator(object):
… pass
…
создаст в памяти объект с именемObjectCreator
. этоОбъекты (объекты класса ObjectCreator) имеют возможность создавать объекты (экземпляры объектов).但是,它的本质仍然是一个对象,于是乎你可以对它做如下的操作:
- вы можете назначить его переменной
- ты можешь скопировать это
- вы можете добавить к нему свойства
- Вы можете передать его как параметр функции
Следующий пример:
In [39]: class ObjectCreator(object):
...: pass
...:
In [40]: print(ObjectCreator)
<class '__main__.ObjectCreator'>
In [41]:# 当作参数传递
In [41]: def out(obj):
...: print(obj)
...:
In [42]: out(ObjectCreator)
<class '__main__.ObjectCreator'>
In [43]: # hasattr 判断一个类是否有某种属性
In [44]: hasattr(ObjectCreator, 'name')
Out[44]: False
In [45]: # 新增类属性
In [46]: ObjectCreator.name = 'hui'
In [47]: hasattr(ObjectCreator, 'name')
Out[47]: True
In [48]: ObjectCreator.name
Out[48]: 'hui'
In [49]: # 将类赋值给变量
In [50]: obj = ObjectCreator
In [51]: obj()
Out[51]: <__main__.ObjectCreator at 0x212596a7248>
In [52]:
2. Динамически создавать классы
Поскольку классы - это объекты, вы можете создавать динамические их во время выполнения, как и любой другой объект. Во-первых, вы можете создать класс в функции, используйтеclass
ключевые слова подойдут.
def cls_factory(cls_name):
"""
创建类工厂
:param: cls_name 创建类的名称
"""
if cls_name == 'Foo':
class Foo():
pass
return Foo # 返回的是类,不是类的实例
elif cls_name == 'Bar':
class Bar():
pass
return Bar
IPython викторина
MyClass = cls_factory('Foo')
In [60]: MyClass
Out[60]: __main__.cls_factory.<locals>.Foo # 函数返回的是类,不是类的实例
In [61]: MyClass()
Out[61]: <__main__.cls_factory.<locals>.Foo at 0x21258b1a9c8>
Но это недостаточно динамично, потому что вам все равно придется кодировать весь класс самостоятельно. Поскольку классы являются объектами, они должны быть чем-то сгенерированы.
Интерпретатор Python автоматически создает этот объект, когда вы используете ключевое слово class. Но, как и большинство вещей в Python, Python по-прежнему дает вам возможность сделать это вручную.
3. Используйте тип для создания класса
type также имеет совершенно другую функцию, динамически создавая классы.
описать тип класса, принимается в качестве аргумента и возвращает a. (Вы знаете, в зависимости от переданных аргументов, одна и та же функция может иметь два совершенно разных использования — это глупо, но это для того, чтобы поддерживать обратную совместимость в Python)
Тип может работать следующим образом:
тип (имя класса, кортеж, состоящий из имен родительских классов (для наследования может быть пустым), словарь, содержащий атрибуты (имя и значение))
Например следующий код:
In [63]: class Test:
...: pass
...:
In [64]: Test()
Out[64]: <__main__.Test at 0x21258b34048>
In [65]:
Его можно создать вручную следующим образом:
In [69]:# 使用type定义类
In [69]: Test2 = type('Test2', (), {})
In [70]: Test2()
Out[70]: <__main__.Test2 at 0x21259665808>
Мы используемTest2
Как имя класса, и его также можно использовать как переменную для ссылки на класс. Классы и переменные разные, и здесь нет смысла все усложнять. То есть первый аргумент в функции типа также может быть назван другим именем, которое представляет собой имя класса
In [71]: UserCls = type('User', (), {})
In [72]: print(UserCls)
<class '__main__.User'>
In [73]:
использоватьhelp
Чтобы проверить эти две категории
In [74]: # 用 help 查看 Test类
In [75]: help(Test)
Help on class Test in module __main__:
class Test(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
In [76]: # 用 help 查看 Test2类
In [77]: help(Test2)
Help on class Test2 in module __main__:
class Test2(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
In [78]:
4. Используйте type для создания класса с атрибутами
type принимает словарь для определения свойств класса, поэтому
Parent = type('Parent', (), {'name': 'hui'})
можно перевести как:
class Parent(object):
name = 'hui'
и может бытьParent
Используйте его как обычный класс:
In [79]: Parent = type('Parent', (), {'name': 'hui'})
In [80]: print(Parent)
<class '__main__.Parent'>
In [81]: Parent.name
Out[81]: 'hui'
In [82]: p = Parent()
In [83]: p.name
Out[83]: 'hui'
Конечно, вы можете наследовать этот класс, код выглядит следующим образом:
class Child1(Parent):
name = 'jack'
sex = '男'
class Child2(Parent):
name = 'mary'
sex = '女'
можно записать как:
Child1 = type('Child1', (Parent, ), {'name': 'jack', 'sex': '男'})
In [85]: Child2 = type('Child2', (Parent, ), {'name': 'mary', 'sex': '女'})
In [87]: Child1.name, Child1.sex
Out[87]: ('jack', '男')
In [88]: Child2.name, Child2.sex
Out[88]: ('mary', '女')
Уведомление:
- Второй параметр типа,Кортеж — это имя родительского класса, а не строка
- Дополнительным свойством являетсяатрибут класса, а не свойство экземпляра
5. Используйте type для создания класса с методами
В конце концов вы захотите добавить методы в свой класс. Просто определите функцию с правильной подписью и назначьте ее как свойство.
добавить метод экземпляра
In [89]: Parent = type('Parent', (), {'name': 'hui'})
In [90]: # 定义函数
In [91]: def get_name(self):
...: return self.name
...:
In [92]: Child3 = type('Child3', (Parent, ), {'name': 'blob', 'get_name': get_name})
In [93]: c3 = Child3()
In [94]: c3.name
Out[94]: 'blob'
In [95]: c3.get_name()
Out[95]: 'blob'
добавить статический метод
In [96]: Parent = type('Parent', (), {'name': 'hui'})
In [97]: # 定义静态方法
In [98]: @staticmethod
...: def test_static():
...: print('static method called...')
...:
In [100]: Child4 = type('Child4', (Parent, ), {'name': 'zhangsan', 'test_static': test_static})
In [101]: c4 = Child4()
In [102]: c4.test_static()
static method called...
In [103]: Child4.test_static()
static method called...
добавить метод класса
In [105]: Parent = type('Parent', (), {'name': 'hui'})
In [106]: # 定义类方法
In [107]: @classmethod
...: def test_class(cls):
...: print(cls.name)
...:
In [108]: Child5 = type('Child5', (Parent, ), {'name': 'lisi', 'test_class': test_class})
In [109]: c5 = Child5()
In [110]: c5.test_class()
lisi
In [111]: Child5.test_class()
lisi
Как видите, в Python классы также являются объектами, и вы можете создавать классы динамически. ЭтоКогда вы используете ключевое словоclass
ВремяPython
То, что делается за кулисами, достигается через метакласс.
Более полный способ создания класса с использованием типа:
class Animal(object):
def eat(self):
print('吃东西')
def dog_eat(self):
print('喜欢吃骨头')
def cat_eat(self):
print('喜欢吃鱼')
Dog = type('Dog', (Animal, ), {'tyep': '哺乳类', 'eat': dog_eat})
Cat = type('Cat', (Animal, ), {'tyep': '哺乳类', 'eat': cat_eat})
# ipython 测验
In [125]: animal = Animal()
In [126]: dog = Dog()
In [127]: cat = Cat()
In [128]: animal.eat()
吃东西
In [129]: dog.eat()
喜欢吃骨头
In [130]: cat.eat()
喜欢吃鱼
6. Что такое метакласс (наконец-то по теме)
Метакласс — это то, что используется для создания класса.. Вы создаете классы для создания экземпляров объектов класса, не так ли? Но мы уже узнали, что классы в Python также являются объектами.
Метакласс используется для создания этих классов (объектов), метакласс — это класс класса, вы можете понять это так:
MyClass = MetaClass() # 使用元类创建出一个对象,这个对象称为“类”
my_object = MyClass() # 使用“类”来创建出实例对象
Вы видели, что этот тип позволяет вам делать что-то вроде:
MyClass = type('MyClass', (), {})
Это связано с тем, что функцияtype
Фактически метакласс.type
это метакласс, который Python использует за кулисами для создания всех классов. Теперь вы задаетесь вопросом, почему все буквы type написаны строчными буквами, а не Type? Ну, я думаю, это сделано для согласованности с str , который является классом, используемым для создания строковых объектов, а int — это класс, используемый для создания целочисленных объектов. type — это класс, создающий объект класса. вы можете проверить по__class__
свойства, чтобы увидеть это. следовательноВсе в Python является объектом
Теперь для любого__class__
из__class__
Что такое атрибут?
In [136]: a = 10
In [137]: b = 'acb'
In [138]: li = [1, 2, 3]
In [139]: a.__class__.__class__
Out[139]: type
In [140]: b.__class__.__class__
Out[140]: type
In [141]: li.__class__.__class__
Out[141]: type
In [142]: li.__class__.__class__.__class__
Out[142]: type
Таким образом, метакласс — это то, что создает объект, подобный классу. type — это встроенный метакласс Python, конечно, вы также можете создать свой собственный метакласс.
7. __metaclass__
Атрибуты
Вы можете добавить его при определении класса__metaclass__
Атрибуты.
class Foo(object):
__metaclass__ = something…
...省略...
Если вы это сделаете, Python будет использовать метакласс для создания класса Foo. Будьте осторожны, здесь есть уловки. ты первый напишиclass Foo(object)
, но класс Foo не был создан в памяти. Python будет искать в определении класса__metaclass__
атрибут, если он найден, Python будет использовать его для создания класса Foo, если не найден, будет использовать встроенныйtype
для создания этого класса.
class Foo(Bar):
pass
Питон делает следующее:
- Фу имеет
__metaclass__
Этот атрибут это? Если есть, Python пройдет__metaclass__
Создайте класс (объект) с именем Foo - Если Python не находит
__metaclass__
, это будет продолжатьсяБар (родительский класс)находясь в поиске__metaclass__
свойства и попробуйте сделать то же самое, что и раньше. - Если Python не найден ни в одном родительском классе
__metaclass__
, он будет выглядеть в иерархии модулей__metaclass__
, и попробуйте сделать то же самое. - Если вы все еще не можете найти его
__metaclass__
, Python будет использовать встроенныйtype
для создания этого объекта класса.
Теперь вопрос в том, что вы можете__metaclass__
Какой код туда вставить?
Ответ таков: вы можете создать класс вещей. Так что же можно использовать для создания класса? тип или любой тип, который использует тип или его подклассы.
8. Пользовательские метаклассы
Основная цель метаклассов — автоматически изменять классы при их создании.
Представьте себе глупый пример, когда вы решаете, что все атрибуты класса в вашем модуле должны быть в верхнем регистре. Есть несколько способов сделать это, но один из них — установить на уровне модуля__metaclass__
. Таким образом, все классы в этом модуле будут создаваться через этот метакласс, нам просто нужно указать метаклассу изменить все свойства на верхний регистр, и все будет хорошо.
К счастью,__metaclass__
На самом деле его можно вызывать произвольно, он не обязательно должен быть формальным классом. Итак, давайте начнем с простой функции в качестве примера.
питон2
# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):
# class_name 会保存类的名字 Foo
# class_parents 会保存类的父类 object
# class_attr 会以字典的方式保存所有的类属性
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 调用type来创建一个类
return type(class_name, class_parents, new_attr)
class Foo(object):
__metaclass__ = upper_attr # 设置Foo类的元类为upper_attr
bar = 'bip'
print(hasattr(Foo, 'bar'))
# Flase
print(hasattr(Foo, 'BAR'))
# True
f = Foo()
print(f.BAR)
питон3
# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):
#遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name,value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
#调用type来创建一个类
return type(class_name, class_parents, new_attr)
# 再类的继承()中使用metaclass
class Foo(object, metaclass=upper_attr):
bar = 'bip'
print(hasattr(Foo, 'bar'))
# Flase
print(hasattr(Foo, 'BAR'))
# True
f = Foo()
print(f.BAR)
Сделай это снова, на этот раз с настоящимclass
как метакласс.
class UpperAttrMetaClass(type):
def __new__(cls, class_name, class_parents, class_attr):
# 遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 方法1:通过'type'来做类对象的创建
return type(class_name, class_parents, new_attr)
# 方法2:复用type.__new__方法
# 这就是基本的OOP编程,没什么魔法
# return type.__new__(cls, class_name, class_parents, new_attr)
# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
bar = 'bip'
# python2的用法
class Foo(object):
__metaclass__ = UpperAttrMetaClass
bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出: True
f = Foo()
print(f.BAR)
# 输出: 'bip'
__new__ 是在__init__之前被调用的特殊方法
__new__是用来创建对象并返回之的方法
而__init__只是用来将传入的参数初始化给对象
这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
Вот и все, кроме этого, о метаклассах действительно больше нечего сказать. Но что касается самих метаклассов, то они на самом деле довольно просты:
- Создание класса перехвата
- Изменить класс
- Возвращает класс после модификации
С какой стати вы используете метаклассы?
Теперь вернемся к нашей большой теме, с какой стати вам использовать такую подверженную ошибкам и непонятную функцию?
Ну, в общем-то, вам это совершенно не нужно:
«Метаклассы — это глубокая магия, и 99% пользователей вообще не должны об этом беспокоиться. Если вы пытаетесь понять, нужно ли вам вообще использовать метаклассы, то вам это не нужно. использовать метаклассы знают это очень хорошо. Они точно знают, что им нужно делать, и им не нужно объяснять, почему метаклассы вообще используются», — Тим Питерс, лидер мира Python.
исходный код
Исходный код загружен наGitee
PythonKnowledge: хранилище знаний Python, добро пожаловать всем в гости.
✍ Кодировать слова непросто, надеюсь, вы все нас поддержите ❤️.
Нет публики
новая папкаX
Природе понадобились десятки миллиардов лет, чтобы создать наш реальный мир, а программистам понадобились сотни лет, чтобы создать совершенно другой виртуальный мир. Мы используем наши клавиатуры, чтобы выковывать кирпичи и кирпичи, и мы используем наши мозги, чтобы все строить. Люди считают 1000 авторитетом, мы делаем наоборот и защищаем позицию 1024. Мы не клавишные воины, мы просто выдающиеся творцы в обычном мире.